package com.cti.ftpservice.ftp;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;

import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPFileFilter;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.cti.ftpservice.utils.FtpConfigInfo;
import com.cti.ftpservice.utils.WsPropertiesLoadUtil;
import com.cti.ftpservice.utils.XmlFtpFileFilter;
import com.cti.ftpservice.vo.FtpDownLoadBaseServiceInfoVo;
import com.cti.ftpservice.vo.FtpFileInfoVo;
import com.ctibook.booksystem.ws.FtpFileInfoViewVo;
import com.ctibook.booksystem.ws.FtpServiceViewVo;
import com.ctibook.booksystem.ws.FtpServiceWS;

@Component
public class FileUtils {

	private static Log logger = LogFactory.getLog(FileUtils.class);
    // FTP协议里面，规定文件名编码为iso-8859-1  
    private static String SERVER_CHARSET = "ISO-8859-1"; 

    private static FileUtils fileUtils;
    
    @Autowired
    private  FtpServiceWS ftpServiceWS;
    
    @PostConstruct //@PostConstruct修饰的方法会在服务器加载Servle的时候运行，并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行
    public void init() {
    	fileUtils = this;
    	fileUtils.ftpServiceWS = this.ftpServiceWS;
    } 
    
	public static List<FtpFileInfoVo> getFilesFromFilePaths(List<String> ftpfilePaths,FtpServiceViewVo ftpServiceViewVo,String localRootPath){
		List<FtpFileInfoVo> fileFullInfos=new ArrayList<FtpFileInfoVo>();
		try {
			FTPClientHelper ftpClient=new FTPClientHelper();
			if(ftpfilePaths!=null && ftpfilePaths.size()>0){
				for(String filePath :ftpfilePaths){
					if(!ftpClient.isConnected())
				    	FtpCliectConnect(ftpClient,ftpServiceViewVo);
					FTPFile[] files = ftpClient.listFiles(new String(filePath.getBytes(ftpClient.getLOCAL_CHARSET()),SERVER_CHARSET));
					for (FTPFile ftpFile : files) {
						List<FtpFileInfoVo> ftpFiles= downloadFileFromFtpService(ftpClient,ftpFile,filePath,ftpServiceViewVo,localRootPath);
						for(FtpFileInfoVo file :ftpFiles){
							fileFullInfos.add(file);
						}
					}
				}
			}else{
				if(!ftpClient.isConnected())
			    	FtpCliectConnect(ftpClient,ftpServiceViewVo);
				FTPFile[] files = ftpClient.listFiles();
				for (FTPFile ftpFile : files) {
					List<FtpFileInfoVo> ftpFiles= downloadFileFromFtpService(ftpClient,ftpFile,"\\",ftpServiceViewVo,localRootPath);
					for(FtpFileInfoVo file :ftpFiles){
						fileFullInfos.add(file);
					}
				}
			}
		} catch (IOException e) {
			logger.error("获取"+ftpServiceViewVo.getFtpServiceName()+"Ftp服务器 文件失败;"+e.getMessage()); 
		}
		return fileFullInfos;
	}
	
	private static void FtpCliectConnect(FTPClientHelper ftpClient,FtpServiceViewVo ftpServiceViewVo) throws NumberFormatException, IOException{
		CommonsFtpUtils.connect(ftpClient, ftpServiceViewVo.getUrl(), Integer.parseInt(ftpServiceViewVo.getPort()), ftpServiceViewVo.getUserName(), ftpServiceViewVo.getPassWrod());
	}
	

	private static List<FtpFileInfoVo> downloadFileFromFtpService(FTPClientHelper ftpClient,FTPFile ftpFile,String fileDirPath,FtpServiceViewVo ftpServiceViewVo,String localRootPath) throws IOException {
       List<FtpFileInfoVo> downloadFtpFiles= new ArrayList<FtpFileInfoVo>();
       if(!ftpClient.isConnected())
    	   FtpCliectConnect(ftpClient,ftpServiceViewVo);
		if(ftpFile.isFile()){
    	  FtpFileInfoVo	fileInfo=getFtpFileInfoByFilePath(ftpServiceViewVo.getUrl(),fileDirPath+ftpFile.getName(),ftpFile.getSize(),localRootPath);
          if(fileInfo!=null)
        	  downloadFtpFiles.add(fileInfo);
		}else if(ftpFile.isDirectory()){
			//String fileName= new String(ftpFile.getName().getBytes("utf-8"),"utf-8").replace(".", "");
			String fileName= ftpFile.getName().replace(".", "");
			if(fileName.length()>0){
				String fileRootPath= fileDirPath.trim().length()>0?fileDirPath.substring(0, fileDirPath.length()-1):"";
				String filePath= fileRootPath+"/"+fileName+"/";
				FTPFile[] dirFtpFiles= ftpClient.listFiles(new String(filePath.getBytes(ftpClient.getLOCAL_CHARSET()),SERVER_CHARSET));
				for(FTPFile dirftpFile :dirFtpFiles){
					List<FtpFileInfoVo> dirdownloadFtpFiles= downloadFileFromFtpService(ftpClient,dirftpFile,filePath,ftpServiceViewVo,localRootPath);	
				    for(FtpFileInfoVo file :dirdownloadFtpFiles){
				    	downloadFtpFiles.add(file);
				    }
				}	
			}
		}
		return downloadFtpFiles;
	}




	public static void getChildrenFilesFromExistPath(String path,List<FtpFileInfoVo> resultFilePaths,FTPClientHelper ftpClient,String hostname,int port,String username,String password,String localRootPath){
			try {
				if(!ftpClient.isConnected())
					CommonsFtpUtils.connect(ftpClient, hostname, port, username, password);
				FTPFile[] files = ftpClient.listFiles(new String(path.getBytes(ftpClient.getLOCAL_CHARSET()),SERVER_CHARSET));
				if(files.length==1){
					if(files[0].isFile()){
						FtpFileInfoVo	fileInfo=getFtpFileInfoByFilePath(hostname,path,files[0].getSize(),localRootPath);
						if(fileInfo!=null)
							resultFilePaths.add(fileInfo);
					}
				}else{
					for (FTPFile ftpFile : files) {
						getChildrenFilesFromExistPath(path+"\\"+ftpFile.getName(),resultFilePaths,ftpClient,hostname,port,username,password,localRootPath);
					}
				}
			} catch (IOException e) {
				logger.error(e.getMessage());
			}
	}
	
	public static FtpFileInfoVo getFtpFileInfoByFilePath(String hostname,String filePath,long fileSize,String localRootPath){
		File file=new File(filePath);
		FtpFileInfoVo ftpFileInfo=new FtpFileInfoVo();
		ftpFileInfo.setDownLoadDate(new Date());
		ftpFileInfo.setFtpServicePath(filePath);
		filePath = filePath.replace("/", "\\");
		ftpFileInfo.setLocalFtpPath(localRootPath+filePath);
		String fileName=file.getName();
		ftpFileInfo.setFileName(fileName);
		ftpFileInfo.setFileSize(fileSize);
		ftpFileInfo.setExtension(fileName.substring(fileName.lastIndexOf(".")+1));
		ftpFileInfo.setFtpServiceUrl(hostname);
		
		//ftpFileInfo.setId(id);
		return ftpFileInfo;
	}
	
	/**
	 * 将下载的记录保存在xml文件里
	 * @param infos
	 */
	public static void writeDownLoadFilePaths(String serverId,List<FtpFileInfoVo> infos){
		
		try {
			if(infos==null||infos.size()==0)
				return;
			 Element root = DocumentHelper.createElement("Objects"); 
			 Document doucment = DocumentHelper.createDocument(root);
			 root.addAttribute("name",infos.get(0).getFtpServiceUrl());
			 root.addAttribute("id",serverId);
			 for (FtpFileInfoVo ftpFileInfo : infos) {
				 Element fileInfo = root.addElement("FileInfo");
				 fileInfo.addAttribute("name", ftpFileInfo.getFileName()); 
				 fileInfo.addAttribute("extension", ftpFileInfo.getExtension());
				 fileInfo.addAttribute("fileType", ftpFileInfo.getFlieType()); 
				 fileInfo.addAttribute("localFtpPath", ftpFileInfo.getLocalFtpPath()); 
				 fileInfo.addAttribute("date", DateHelper.toStirng(ftpFileInfo.getDownLoadDate(), "yyyy-MM-dd hh:mm:ss")); 
				 fileInfo.addAttribute("fileSize", String.valueOf(ftpFileInfo.getFileSize()));
				 fileInfo.addAttribute("ftpServicePath", ftpFileInfo.getFtpServicePath());
			}
			 FtpConfigInfo ftpConfigInfo=new FtpConfigInfo();
			 String savePath= ftpConfigInfo.getFtpDownloadFileSaveXmlPathRoot()+DateHelper.toStirng(new Date(), "yyyyMMddhhmmss")+"downloadFileinfos.xml";
			 File f=new File(savePath);
			 if(!f.getParentFile().exists()){
				 f.getParentFile().mkdirs();
				 f.createNewFile();
			 }
	         OutputFormat format = new OutputFormat("    ",true); 
	         format.setEncoding("GBK");
	         FileOutputStream file = new FileOutputStream(savePath);  
	         XMLWriter xmlwriter = new XMLWriter(file,format);  
			 xmlwriter.write(doucment); 
			 xmlwriter.close();  
		} catch (Exception e) {
			logger.error(e.getMessage());
		}  
        
	}
	
	/**
	 * 将下载文件的明细保存到数据库
	 * @throws RemoteException 
	 */
	public static void  saveDownLoadFileInfoToDB(String serverId,List<FtpFileInfoVo> infos,String fileType)   {
		try {
			logger.info("开始保存文件明细到数据库");
			if(infos!=null&&infos.size()>0){
				List<FtpFileInfoViewVo> vos=new ArrayList<FtpFileInfoViewVo>();
				for (FtpFileInfoVo ftpFileInfo : infos) {
					FtpFileInfoViewVo vo = new FtpFileInfoViewVo();
					vo.setFtpServiceId(serverId);
					vo.setApprovedByHuman(false);
					vo.setFlieType(fileType);//extension
					vo.setExtension(ftpFileInfo.getExtension());
					vo.setFileName(ftpFileInfo.getFileName());
					vo.setLocalFtpFilePath(ftpFileInfo.getLocalFtpPath());
					vo.setDownloadFtpFilePath(ftpFileInfo.getFtpServicePath());
					vo.setDownloadDate(DateHelper.toStirng(ftpFileInfo.getDownLoadDate(), "yyyy-MM-dd hh:mm:ss"));
					vo.setFileSize(ftpFileInfo.getFileSize());
					vos.add(vo);
				}
				fileUtils.ftpServiceWS.addOrUpdateFtpFileInfoViewVos(vos);
				logger.info("下载文件明细已保存至数据库");
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
	}

	public static List<FtpFileInfoVo> getFilesFromFilePaths(String[] ftpfilePaths,String hostname,int port,String username,String password,String localRootPath){
		List<FtpFileInfoVo> fileFullInfos=new ArrayList<FtpFileInfoVo>();
		try {
			FTPClientHelper ftpClient=new FTPClientHelper();
			CommonsFtpUtils.connect(ftpClient, hostname, port, username, password);
			for (String ftpfilePath : ftpfilePaths) {
				FTPFile[] files = ftpClient.listFiles(new String(ftpfilePath.getBytes(ftpClient.getLOCAL_CHARSET()),SERVER_CHARSET));
				if(files.length==1){
					FtpFileInfoVo	fileInfo=getFtpFileInfoByFilePath(hostname,files[0].getName(),files[0].getSize(),localRootPath);
					if(fileInfo!=null)
						fileFullInfos.add(fileInfo);
					continue;
				}
				for (FTPFile ftpFile : files) {
					getChildrenFilesFromExistPath(ftpfilePath+"\\"+ftpFile.getName(),fileFullInfos,ftpClient,hostname,port,username,password,localRootPath);
				}
			}
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		return fileFullInfos;
	}
	
	public static List<FtpFileInfoVo> getXmlFilesFromFtpServiceFile(List<String> ftpfilePaths,String hostname,int port,String username,String password,String localRootPath){
		List<FtpFileInfoVo> fileFullInfos=new ArrayList<FtpFileInfoVo>();
		try {
			FTPClientHelper ftpClient=new FTPClientHelper();
			CommonsFtpUtils.connect(ftpClient, hostname, port, username, password);
			for (String ftpfilePath : ftpfilePaths) {
				getChildrenXmlFilesFromExistPath(ftpfilePath,new XmlFtpFileFilter(),fileFullInfos,ftpClient,hostname,port,username,password,localRootPath);
			}
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		return fileFullInfos;
	}
	
	public static void getChildrenXmlFilesFromExistPath(String path,FTPFileFilter ftpFileFilter, List<FtpFileInfoVo> resultFilePaths,FTPClientHelper ftpClient,String hostname,int port,String username,String password,String localRootPath){
		try {
			if(!ftpClient.isConnected())
				CommonsFtpUtils.connect(ftpClient, hostname, port, username, password);
			FTPFile[] files = ftpClient.listFiles(new String(path.getBytes(ftpClient.getLOCAL_CHARSET()),SERVER_CHARSET),ftpFileFilter);
			for (FTPFile ftpFile : files) {
				if(ftpFile.isFile()){
					FtpFileInfoVo	fileInfo=getFtpFileInfoByFilePath(hostname,path+"\\"+ftpFile.getName(),ftpFile.getSize(),localRootPath);
					if(fileInfo!=null)
						resultFilePaths.add(fileInfo);
				}else{
					getChildrenXmlFilesFromExistPath(path+"\\"+ftpFile.getName(),ftpFileFilter,resultFilePaths,ftpClient,hostname,port,username,password,localRootPath);
				}
			}
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
	}

	
	
}
